//////////////////////////////////////////////
// StringView.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward decl -----------------------------

namespace nkLog
{
	class StringView ;
}

namespace nkMemory
{
	class String ;
}

/// Includes ---------------------------------

// nkMemory
#include "../Dll/DllDefines.h"

#include "BufferCast.h"

// nkLog
#include <NilkinsLog/Data/String.h>
#include <NilkinsLog/Data/StringView.h>

// Standards
#include <string>
#include <string_view>

/// Class ------------------------------------

namespace nkMemory
{
	class DLL_MEMORY_EXPORT StringView final
	{
		public :

			// Constructor, destructor
			StringView () noexcept ;
			StringView (const char* data) noexcept ;
			StringView (const char* data, unsigned long long size) noexcept ;
			StringView (const nkLog::StringView& logStr) noexcept ;
			StringView (const String& other) noexcept ;
			StringView (const StringView& other) noexcept ;
			StringView (StringView&& other) noexcept ;

			// Getters
			const char* getData () const ;
			unsigned long long getSize () const ;
			bool empty () const ;
			char front () const ;
			char back () const ;
			const char* begin () const ;
			const char* end () const ;

			// Utils
			BufferCast<StringView> split (StringView separator) ;

			// Operators
			StringView& operator= (const char* data) noexcept ;
			StringView& operator= (const String& other) noexcept ;
			StringView& operator= (const StringView& other) noexcept ;
			StringView& operator= (StringView&& other) noexcept ;
			char operator[] (unsigned long long index) const ;
			String operator+ (char c) const ;
			String operator+ (const char* data) const ;
			String operator+ (const StringView& other) const ;
			bool operator== (const char* other) const ;
			bool operator== (const StringView& other) const ;
			bool operator!= (const char* other) const ;
			bool operator!= (const StringView& other) const ;

		public :

			// Inlined constructors
			template<typename T = std::string>
			StringView (const std::string& str) noexcept
			:	_data (str.data()),
				_size (str.size())
			{
				// Nothing to do
			}

			template<typename T = std::string>
			StringView (const std::string& str, unsigned long long index, unsigned long long size = 0ull) noexcept
			:	_data (&str[index]),
				_size (size ? size : str.size() - index)
			{
				// Nothing to do
			}

			template<typename T = std::string_view>
			StringView (const std::string_view& str) noexcept
			:	_data (str.data()),
				_size (str.size())
			{
				// Nothing to do
			}

			template<typename T = std::string_view>
			StringView (const std::string_view& str, unsigned long long index, unsigned long long size = 0ull) noexcept
			:	_data (&str[index]),
				_size (size ? size : str.size() - index)
			{
				// Nothing to do
			}

		public :

			// Inlined operators
			template<typename T = std::string>
			operator std::string () const
			{
				return std::string(_data, _size) ;
			}

			template<typename T = std::string_view>
			operator std::string_view () const
			{
				return std::string_view(_data, _size) ;
			}

			operator nkLog::String () const
			{
				return nkLog::String(_data, _size) ;
			}

			operator nkLog::StringView () const
			{
				return nkLog::StringView(_data, _size) ;
			}

			template<typename T = std::string>
			StringView& operator= (const std::string& data)
			{
				_data = data.data() ;
				_size = data.size() ;

				return *this ;
			}

			template<typename T = std::string_view>
			StringView& operator= (const std::string_view& data)
			{
				_data = data.data() ;
				_size = data.size() ;

				return *this ;
			}

		private :

			// Attributes
			// Data info
			const char* _data ;
			unsigned long long _size ;
	} ;

	// Globals
	// Operators
	inline bool operator== (const char* c, const nkMemory::StringView& str)
	{
		return str == c ;
	}
}